/*
 *
 *   Copyright (C) 2005 by Raymond Huang
 *   plushuang at users.sourceforge.net
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  ---
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU Lesser General Public License in all respects
 *  for all of the code used other than OpenSSL.  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so.  If you
 *  do not wish to do so, delete this exception statement from your
 *  version.  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 *
 */

#include <glib.h>
#include <string.h>
#include <urlglib/url_info.h>

// UrlInfo -----------------------------------------------------------

void url_info_init (UrlInfo* uli)
{
	memset (uli, 0, sizeof (UrlInfo));
}

UrlInfo* url_info_new (const char* url_str)
{
	UrlInfo* uli = g_malloc (sizeof (UrlInfo));

	url_info_part (uli, url_str);
	return uli;
}

UrlInfo* url_info_new_len (const char* url_str, int len)
{
	UrlInfo* uli = g_malloc (sizeof (UrlInfo));

	url_info_part_len (uli, url_str, len);
	return uli;
}

UrlInfo* url_info_new_path (const char* path_str)
{
	UrlInfo* uli = g_malloc (sizeof (UrlInfo));

	url_info_part_path (uli, path_str);
	return uli;
}

UrlInfo* url_info_new_path_len (const char* path_str, int len)
{
	UrlInfo* uli = g_malloc (sizeof (UrlInfo));

	url_info_part_path_len (uli, path_str, len);
	return uli;
}

void url_info_free (UrlInfo* uli)
{
	g_free (uli);
}

int  url_info_part_len (UrlInfo* uli, const char* str, int len)
{
	char  chr;
	int   index, index2;
	int   continue_flag;
	int   result = FALSE;

	// initialize
	url_info_init (uli);
	if (len == -1)
		len = strlen (str);

	// protocol
	for (index=0; index<len; index++) {
		chr = str[index];
		if ( (chr>='a' && chr<='z') || (chr>='A' && chr<='Z') || (chr >= '0' && chr <= '9') ||
		      chr == '%' || chr=='+' || chr=='-' || chr == '.')
			continue;
		if (chr == ':' && index!=0 && len - index >= 3 && str[index+1]=='/' && str[index+2]=='/') {
			uli->protocol     = str;
			uli->protocol_len = index;
			index += 3;
			result = TRUE;
			break;
		}
		else {
			url_info_part_path_full (uli, str, len, TRUE, FALSE);
			return FALSE;
		}
	}

	// id:password and address:port
	for (index2=index, continue_flag=TRUE; continue_flag; ++index) {
		if (index == len) {
			if (index2 == len)
				break;
			chr = '/';    // this will break loop
		}
		else
			chr = str[index];

		switch (chr) {
		case '/':
			continue_flag = FALSE;    // break loop
		case '@':
			if (uli->address) {
				uli->port     = str + index2;
				uli->port_len = index - index2;
				break;
			}
		case ':':
			uli->address     = str + index2;
			uli->address_len = index - index2;
			index2 = index+1;
			break;
		}
		if (chr == '@' && uli->id == NULL) {
    		// swap address:port and id:password
			uli->id     = uli->address;
			uli->id_len = uli->address_len;
			uli->password     = uli->port;
			uli->password_len = uli->port_len;

			uli->address     = NULL;
			uli->address_len = 0;
			uli->port     = NULL;
			uli->port_len = 0;
			index2 = index+1;
		}
	}

	uli->location_len = index;

	if (index < len)
		url_info_part_path_full (uli, str + index, len - index, TRUE, FALSE);

	return result;
}

void url_info_part_path_full (UrlInfo* uinfo, const char* str, int len, int is_url, int need_init)
{
	int  continue_flag;
	int  index_beg, index, index_tmp;
	char dir_separator;
	char chr;

	// initialize
	if (need_init)
		url_info_init (uinfo);
	if (len == -1)
		len = strlen (str);

	if (is_url)
		dir_separator = '/';
	else
		dir_separator = G_DIR_SEPARATOR;

	// directory
	uinfo->path = str;
	for (index=0, index_tmp=0, chr=0; ; index++) {
		if (index == len || chr == '?') {
			uinfo->path_len = index_tmp;
			uinfo->dir_len  = index_tmp;
			index = index_tmp;
			break;
		}
		if (str[index] == dir_separator)
			index_tmp = index + 1;
	}
	if (uinfo->location_len)
		uinfo->location_len += index_tmp;

	// filename, ext, and query
	for (index_beg=index, continue_flag=TRUE; continue_flag; ++index) {
		if (index == len) {
			if (index_beg == len)
				break;
			chr = 0;    // this will break loop
		}
		else
			chr = str[index];

		switch (chr) {
		case '?':
			uinfo->query     = str + index +1;
			uinfo->query_len = len - index -1;
		case 0:
			continue_flag = FALSE;    // break loop
			uinfo->filename      = str + index_beg;
			uinfo->filename_len  = index - index_beg;
			uinfo->path_len     += uinfo->filename_len;
			if (uinfo->main_filename_len) {
				uinfo->ext_filename     = str + index_tmp;
				uinfo->ext_filename_len = index - index_tmp;
				break;
			}
		case '.':
			uinfo->main_filename_len = index - index_beg;
			index_tmp = index + 1;
			break;
		}
	}
}

static int hex_char_2_int (char chr)
{
	if (chr >= '0' && chr <= '9')
		return chr - '0';
	if (chr >= 'A' && chr <= 'F');
		return chr - 'A' + 10;
//	if (chr >= 'a' && chr <= 'f');
		return chr - 'a' + 10;
}

char* url_info_get_filename (UrlInfo* uli)
{
 	GString* gstr;
	const char* p_cur;
	const char* p_end;
	char  chr;

	if (uli->filename_len == 0)
		return NULL;

	gstr = g_string_sized_new (uli->filename_len);
	p_end = uli->filename + uli->filename_len;

	for (p_cur=uli->filename; p_cur != p_end; p_cur++) {
		chr = *p_cur;
		if (chr == '%' && p_cur+2 < p_end) {
			chr  = hex_char_2_int (p_cur[1]) << 4;
			chr += hex_char_2_int (p_cur[2]);
			p_cur += 2;
		}
		g_string_append_c (gstr, chr);
	}
	return g_string_free (gstr, FALSE);
}

